其他
Kotlin委托的原理与使用,在Android中常用的几个场景
本文作者
作者:newki
链接:
https://juejin.cn/post/7213267574770090039
本文由作者授权发布。
前言
接口/类的委托 属性的委托 结合lazy的延迟委托 观察者的委托 Map数据的委托
下面我们就一起看看不同种类的委托使用以及在 Android 常见的一些场景中的使用。
interface IUserAction {
fun attack()
fun defense()
}
class UserActionImpl : IUserAction {
override fun attack() {
YYLogUtils.w("默认操作-开始执行攻击")
}
override fun defense() {
YYLogUtils.w("默认操作-开始执行防御")
}
}
class UserDelegate1(private val action: IUserAction) : IUserAction {
override fun attack() {
YYLogUtils.w("UserDelegate1-需要自己实现攻击")
}
override fun defense() {
YYLogUtils.w("UserDelegate1-需要自己实现防御")
}
}
class UserDelegate2(private val action: IUserAction) : IUserAction by action
class UserDelegate3(private val action: IUserAction) : IUserAction by action {
override fun attack() {
YYLogUtils.w("UserDelegate3 - 只重写了攻击")
}
}
val actionImpl = UserActionImpl()
UserDelegate1(actionImpl).run {
attack()
defense()
}
UserDelegate2(actionImpl).run {
attack()
defense()
}
UserDelegate3(actionImpl).run {
attack()
defense()
}
class AnimUtil private constructor() : DefaultLifecycleObserver {
...
private fun addLoopLifecycleObserver() {
mOwner?.lifecycle?.addObserver(this)
}
// 退出页面的时候释放资源
override fun onDestroy(owner: LifecycleOwner) {
mAnim?.cancel()
destory()
}
}
/**
* 定义是否需要SAFLauncher
*/
interface ISAFLauncher {
fun <T : ActivityResultCaller> T.initLauncher()
fun getLauncher(): GetSAFLauncher?
}
class SAFLauncher : ISAFLauncher {
private var safLauncher: GetSAFLauncher? = null
override fun <T : ActivityResultCaller> T.initLauncher() {
safLauncher = GetSAFLauncher(this)
}
override fun getLauncher(): GetSAFLauncher? = safLauncher
}
class DemoActivity : BaseActivity, ISAFLauncher by SAFLauncher() {
override fun init() {
initLauncher() // 实现了接口还需要初始化Launcher
}
fun gotoOtherPage() {
//使用 Result Launcher 的方式启动,并获取到返回值
getLauncher()?.launch<DemoCircleActivity> { result ->
val result = result.data?.getStringExtra("text")
toast("收到返回的数据:$result")
}
}
}
这样是不是就非常简单了呢?具体如何使用封装 Result Launcher 可以看看我去年的文章 【传送门】
https://juejin.cn/post/7136359176564899877
private val textStr by "123"
private val textStr by TextDelegate()
class TextDelegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "我是赋值给与的文本"
}
}
private var textStr by TextDelegate()
class TextDelegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "我是赋值给与的文本"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
YYLogUtils.w("设置的值为:$value")
}
}
YYLogUtils.w("textStr:$textStr")
textStr = "abc123"
class TextDelegate : ReadOnlyProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return "我是赋值给与的文本"
}
}
class TextDelegate : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return "我是赋值给与的文本"
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
YYLogUtils.w("设置的值为:$value")
}
}
private var textStr by TextDelegate2()
private var textStr2 by this::textStr
private val industryName: String
get() {
return "abc123"
}
对于只读的属性,这种方式也是我们常见的使用方式。
val name: String by lazy {
YYLogUtils.w("第一次调用初始化")
"abc123"
}
YYLogUtils.w(name)
YYLogUtils.w(name)
YYLogUtils.w(name)
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
SYNCHRONIZED:添加同步锁,使lazy延迟初始化线程安全。 PUBLICATION:初始化的lambda表达式,可以在同一时间多次调用,但是只有第一次的返回值作为初始化值。 NONE:没有同步锁,非线程安全。
默认情况下,对于 lazy 属性的求值是同步锁的(synchronized),是可以保证线程安全的,但是如果不需要线程安全和减少性能花销可以可以使用lazy(LazyThreadSafetyMode.NONE){} 即可。
var values: String by Delegates.observable("默认值") { property, oldValue, newValue ->
YYLogUtils.w("打印值: $oldValue -> $newValue ")
}
values = "第一次修改"
values = "第二次修改"
values = "第三次修改"
var age: Int by Delegates.vetoable(18) { property, oldValue, newValue ->
newValue > oldValue
}
YYLogUtils.w("age:$age")
age = 14
YYLogUtils.w("age:$age")
age = 20
YYLogUtils.w("age:$age")
age = 22
YYLogUtils.w("age:$age")
age = 20
YYLogUtils.w("age:$age")
虽然这种方式我们并不常用,一般我们都是使用类似 Flow 之类的工具在源头就处理了逻辑,使用这种方式我们就可以在属性的赋值过程中进行拦截了。在一些特定的场景下还是有用的。
class Member(private val map: Map<String, Any>) {
val name: String by map
val age: Int by map
val dob: Long by map
override fun toString(): String {
return "Member(name='$name', age=$age, dob=$dob)"
}
}
val member = Member(mapOf("name" to "guanyu", "age" to 36, Pair("dob", 1234567890L)))
YYLogUtils.w("member:$member")
本文的部分代码可以在我的 Kotlin 测试项目中看到,【传送门】。你也可以关注我的这个Kotlin项目,我有时间都会持续更新。
https://gitee.com/newki123456/Kotlin-Room
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!